<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Highscore - The Boost C++ Libraries - Error Handling</title>
<link rel="stylesheet" href="css/highscore.css" type="text/css">
<link rev="made" href="mailto:boris@highscore.de">
<link rel="home" href="frontpage.html" title="The Boost C++ Libraries">
<link rel="up" href="frontpage.html" title="The Boost C++ Libraries">
<link rel="prev" href="datastructures.html" title="Chapter 14: Data Structures">
<link rel="next" href="castoperators.html" title="Chapter 16: Cast Operators">
<link rel="chapter" href="introduction.html" title="Chapter 1: Introduction">
<link rel="chapter" href="smartpointers.html" title="Chapter 2: Smart Pointers">
<link rel="chapter" href="functionobjects.html" title="Chapter 3: Function Objects">
<link rel="chapter" href="eventhandling.html" title="Chapter 4: Event Handling">
<link rel="chapter" href="stringhandling.html" title="Chapter 5: String Handling">
<link rel="chapter" href="multithreading.html" title="Chapter 6: Multithreading">
<link rel="chapter" href="asio.html" title="Chapter 7: Asynchronous Input and Output">
<link rel="chapter" href="interprocesscommunication.html" title="Chapter 8: Interprocess Communication">
<link rel="chapter" href="filesystem.html" title="Chapter 9: Filesystem">
<link rel="chapter" href="datetime.html" title="Chapter 10: Date and Time">
<link rel="chapter" href="serialization.html" title="Chapter 11: Serialization">
<link rel="chapter" href="parser.html" title="Chapter 12: Parser">
<link rel="chapter" href="containers.html" title="Chapter 13: Containers">
<link rel="chapter" href="datastructures.html" title="Chapter 14: Data Structures">
<link rel="chapter" href="errorhandling.html" title="Chapter 15: Error Handling">
<link rel="chapter" href="castoperators.html" title="Chapter 16: Cast Operators">
<link rel="section" href="errorhandling.html#errorhandling_general" title="15.1 General">
<link rel="section" href="errorhandling.html#errorhandling_system" title="15.2 Boost.System">
<link rel="section" href="errorhandling.html#errorhandling_exception" title="15.3 Boost.Exception">
<meta http-equiv="pics-label" content='(pics-1.1 "http://www.icra.org/ratingsv02.html" l gen true for "http://www.highscore.de" r (nz 1 vz 1 lz 1 oz 1 cz 1) gen true for "http://highscore.de" r (nz 1 vz 1 lz 1 oz 1 cz 1))'>
<meta http-equiv="Content-Style-Type" content="text/css">
<meta http-equiv="Content-Script-Type" content="text/javascript">
<link href="http://www.highscore.de/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon">
<script type="text/javascript" src="js/jquery-1.3.2.min.js"></script><script type="text/javascript" src="js/jquery.event.drag-1.5.min.js"></script><script type="text/javascript" src="js/highscore.js"></script>
</head>
<body>
<div lang="en" class="docbook chapter" title="Chapter 15: Error Handling">
<p class="title">The Boost C++ Libraries</p>
<script type="text/javascript">
          var titlepage = "前言";
        
      var titles = new Array(titlepage,
      
        "第1章: 简介",
      
        "第2章: 智能指针",
      
        "第3章: 函数对象",
      
        "第4章: 事件处理",
      
        "第5章: 字符串处理",
      
        "第6章: 多线程",
      
        "第7章: 异步输入输出",
      
        "第8澡: 进程间通信",
      
        "第9章: 文件系统",
      
        "第10章: 日期与时间",
      
        "第11章: 序列化",
      
        "第12章: 词法分析器",
      
        "第13章: 容器",
      
        "第14章: 数据结构",
      
        "第15章: 错误处理",
      
        "第16章: 转型操作符",
      
      "");

      
          var titlehtml = "frontpage.html";
        
      var filenames = new Array(titlehtml,
      
        "introduction.html",
      
        "smartpointers.html",
      
        "functionobjects.html",
      
        "eventhandling.html",
      
        "stringhandling.html",
      
        "multithreading.html",
      
        "asio.html",
      
        "interprocesscommunication.html",
      
        "filesystem.html",
      
        "datetime.html",
      
        "serialization.html",
      
        "parser.html",
      
        "containers.html",
      
        "datastructures.html",
      
        "errorhandling.html",
      
        "castoperators.html",
      
      "");

      
      document.open();
      document.write('<form action="" class="toc">');
      document.write('<select size="1" onchange="location.href=options[selectedIndex].value">');
      for (var i = 0; i < titles.length && i < filenames.length; ++i) {
        if (titles[i] != "" && filenames[i] != "") {
          document.write('<option');
          document.write(' value="' + filenames[i] + '"');
          var expr = new RegExp('[/\]' + filenames[i] + '$');
          if (expr.test(location.href)) {
            document.write(' selected="selected"');
          }
          document.write('>' + titles[i] + '<\/option>');
        }
      }
      document.write('<\/select>');
      document.write('<\/form>');
      document.close();
      
    </script><noscript><p class="toc"><a href="toc.html">目录</a></p></noscript><hr class="hrhead">
<h1 class="title">
<a name="errorhandling"></a><small>Chapter 15:</small> Error Handling</h1>
<hr>
<div class="toc">
<h3>Table of Contents</h3>
<ul>
<li><span class="sect1"><a href="errorhandling.html#errorhandling_general">15.1 General</a></span></li>
<li><span class="sect1"><a href="errorhandling.html#errorhandling_system">15.2 Boost.System</a></span></li>
<li><span class="sect1"><a href="errorhandling.html#errorhandling_exception">15.3 Boost.Exception</a></span></li>
</ul>
</div>
<p class="license"><a href="http://creativecommons.org/licenses/by-nc-nd/3.0/" rel="license" target="_top"><img src="img/88x31_cc_logo.gif" alt="" width="88" height="31"></a> This book is licensed under a <a href="http://creativecommons.org/licenses/by-nc-nd/3.0/" rel="license" target="_top">Creative Commons License</a>.</p>
<hr>
<h2 class="title">
<a name="errorhandling_general"></a>15.1 General</h2>
<div class="sect1">
<p>Every function having the potential to fail during execution needs a way to communicate this to its caller appropriately. In C++, this is done either by using a return value or by throwing an exception. A return value is usually used if the failure is not really considered exceptional in a common sense. The caller is expected to check the return value and to react accordingly.</p>
<p>Exceptions are used to indicate exceptional conditions that are not considered to happen normally. A good example is the exception of type <code class="exceptionname">std::bad_alloc</code> that is thrown if a dynamic memory allocation using <code class="code">new</code> fails. Since memory can usually be reserved without any issue, it would be cumbersome to always have to check the return value.</p>
<p>This chapter introduces two Boost C++ Libraries assisting a developer in leveraging error handling: Boost.System translates operating system specific error codes into platform independent ones. Thanks to Boost.System, functions returning a value based on an operating system type can be designed in a platform-independent way. Boost.Exception allows to add additional information to any exception that can be utilized inside the <code class="code">catch</code> handler accordingly to better react to the exception.</p>
</div>
<hr>
<h2 class="title">
<a name="errorhandling_system"></a>15.2 Boost.System</h2>
<div class="sect1">
<p><a class="link" href="http://www.boost.org/libs/system/">Boost.System</a>  is a small library defining four classes to identify errors. <code class="classname">boost::system::error_code</code> is the most basic class and represents operating system specific errors. Since operating systems typically enumerate errors, <code class="classname">boost::system::error_code</code> saves an error code in a variable of type <code class="code">int</code>. The following example illustrates how to use this class by accessing the Boost.Asio library.</p>
<pre class="programlisting">#include &lt;boost/system/error_code.hpp&gt; 
#include &lt;boost/asio.hpp&gt; 
#include &lt;iostream&gt; 
#include &lt;string&gt; 

int main() 
{ 
  boost::system::error_code ec; 
  std::string hostname = boost::asio::ip::host_name(ec); 
  std::cout &lt;&lt; ec.value() &lt;&lt; std::endl; 
} </pre>
<ul class="programlisting"><li><a class="programlisting" href="src/15.2.1/main.cpp">Download source code</a></li></ul>
<p>Boost.Asio offers the free-standing <code class="function">boost::asio::ip::host_name()</code> function that returns the name of the computer the application is executed on.</p>
<p>An object of type <code class="classname">boost::system::error_code</code> can be passed as the sole argument to <code class="function">boost::asio::ip::host_name()</code>. If the underlying operating system function fails, this argument contains the corresponding error code. It is also possible to call <code class="function">boost::asio::ip::host_name()</code> without any argument in case the error code is irrelevant.</p>
<p><code class="function">boost::asio::ip::host_name()</code> was actually broken in Boost 1.36.0 and therefore serves as a perfect example. The function possibly returned an error code even though the underlying operating system function did actually return the name of the computer successfully. Since the issue was resolved in Boost 1.37.0, <code class="function">boost::asio::ip::host_name()</code> can now be used without concerns.</p>
<p>Since an error code is nothing but a numeric value, it can be displayed with the help of the <code class="methodname">value()</code>  method. Since the error code 0 usually means that no error has occurred, the meaning of other values depends on the operating system and should be looked up in the manual accordingly.</p>
<p>Compiled on Windows XP using Visual Studio 2008, the above application repeatedly generated error code 14 (not enough storage available to complete the operation) while using Boost 1.36.0. Even though <code class="function">boost::asio::ip::host_name()</code> successfully determined the name of the computer, error code 14 was reported. This behavior is actually due to a broken implementation of <code class="function">boost::asio::ip::host_name()</code>.</p>
<p>Besides <code class="methodname">value()</code>, <code class="classname">boost::system::error_code</code> offers the <code class="methodname">category()</code> method. This method returns an object of the second class defined in Boost.System: <code class="classname">boost::system::category</code>.</p>
<p>Error codes are simply numeric values. While operating system manufacturers such as Microsoft are able to guarantee the uniqueness of system error codes, keeping error codes unique throughout all existing applications is virtually impossible for any application developer. It would require a centralized database filled with error codes by all software developers to avoid reusing the same codes for different scenarios which certainly is impractical. For this reason, error categories exist.</p>
<p>Error codes of type <code class="classname">boost::system::error_code</code> always belong to a category that can be retrieved using the <code class="methodname">category()</code> method. Operating system errors are represented by the predefined object <var>boost::system::system_category</var>.</p>
<p>By calling <code class="methodname">category()</code>, a reference to the predefined <var>boost::system::system_category</var> is returned. It allows to retrieve specific information about the category such as the name using the <code class="methodname">name()</code> method which is <code class="computeroutput">system</code> in case of the system category.</p>
<pre class="programlisting">#include &lt;boost/system/error_code.hpp&gt; 
#include &lt;boost/asio.hpp&gt; 
#include &lt;iostream&gt; 
#include &lt;string&gt; 

int main() 
{ 
  boost::system::error_code ec; 
  std::string hostname = boost::asio::ip::host_name(ec); 
  std::cout &lt;&lt; ec.value() &lt;&lt; std::endl; 
  std::cout &lt;&lt; ec.category().name() &lt;&lt; std::endl; 
} </pre>
<ul class="programlisting"><li><a class="programlisting" href="src/15.2.2/main.cpp">Download source code</a></li></ul>
<p>Errors are uniquely identified by the error code and the error category. Since error codes are only required to be unique within a category, developers should create a new category whenever they want to define error codes specific to an application. This allows for arbitrary error codes that do not interfere with error codes of other developers.</p>
<pre class="programlisting">#include &lt;boost/system/error_code.hpp&gt; 
#include &lt;iostream&gt; 
#include &lt;string&gt; 

class application_category : 
  public boost::system::error_category 
{ 
public: 
  const char *name() const { return "application"; } 
  std::string message(int ev) const { return "error message"; } 
}; 

application_category cat; 

int main() 
{ 
  boost::system::error_code ec(14, cat); 
  std::cout &lt;&lt; ec.value() &lt;&lt; std::endl; 
  std::cout &lt;&lt; ec.category().name() &lt;&lt; std::endl; 
} </pre>
<ul class="programlisting"><li><a class="programlisting" href="src/15.2.3/main.cpp">Download source code</a></li></ul>
<p>A new error category is defined by creating a class derived from <code class="classname">boost::system::error_category</code> and implementing different methods as required by the interface of the new category. At minimum, the methods <code class="methodname">name()</code> and <code class="methodname">message()</code> must be supplied since they are defined as pure virtual in <code class="classname">boost::system::error_category</code>. For additional methods, the default behavior can be overridden accordingly if required.</p>
<p>While <code class="methodname">name()</code> returns the name of the error category, <code class="methodname">message()</code> is used to retrieve the error description for a particular error code. Unlike the above example, the <var>ev</var> parameter is usually evaluated to return a description based on the error code.</p>
<p>Objects of type of the newly created error category can be used to initialize an error code accordingly. The example defines the error code <var>ec</var> using the new <code class="classname">application_category</code> category. Therefore, error code 14 is no longer a system error; its meaning is specified by the developer of the new error category instead.</p>
<p><code class="classname">boost::system::error_code</code> contains a method named <code class="methodname">default_error_condition()</code> which returns an object of type <code class="classname">boost::system::error_condition</code>. The interface of <code class="classname">boost::system::error_condition</code> is almost identical to the one of <code class="classname">boost::system::error_code</code>. The only difference is the <code class="methodname">default_error_condition()</code> method which is only provided by <code class="classname">boost::system::error_code</code>.</p>
<pre class="programlisting">#include &lt;boost/system/error_code.hpp&gt; 
#include &lt;boost/asio.hpp&gt; 
#include &lt;iostream&gt; 
#include &lt;string&gt; 

int main() 
{ 
  boost::system::error_code ec; 
  std::string hostname = boost::asio::ip::host_name(ec); 
  boost::system::error_condition ecnd = ec.default_error_condition(); 
  std::cout &lt;&lt; ecnd.value() &lt;&lt; std::endl; 
  std::cout &lt;&lt; ecnd.category().name() &lt;&lt; std::endl; 
} </pre>
<ul class="programlisting"><li><a class="programlisting" href="src/15.2.4/main.cpp">Download source code</a></li></ul>
<p><code class="classname">boost::system::error_condition</code> is used just like <code class="classname">boost::system::error_code</code>. Both the <code class="methodname">value()</code> and <code class="methodname">category()</code> method can be called for the <code class="classname">boost::system::error_condition</code> object as shown in the above example.</p>
<p>The reason for having two more or less identical classes is fairly simple: While <code class="classname">boost::system::error_code</code> is used for platform dependent error codes, <code class="classname">boost::system::error_condition</code> is used to access platform independent error codes instead. By calling the <code class="methodname">default_error_condition()</code> method, a platform dependent error code is translated into a platform independent error code of type <code class="classname">boost::system::error_condition</code>.</p>
<p>If the above application is executed, it displays the number 12 and the error category <code class="computeroutput">GENERIC</code>. The platform dependent error code 14 has been translated into the platform independent error code 12. Thanks to <code class="classname">boost::system::error_condition</code>, the error is always represented by the same number - disregarding of the underlying platform. While Windows reports the error as 14, the same error may be reported as 25 with a different operating system. Using <code class="classname">boost::system::error_condition</code>, the error will always be reported as 12.</p>
<p>The last class offered by Boost.System is <code class="exceptionname">boost::system::system_error</code> which is derived from <code class="exceptionname">std::runtime_error</code>. It can be used to transport an error code of type <code class="classname">boost::system::error_code</code> within an exception.</p>
<pre class="programlisting">#include &lt;boost/asio.hpp&gt; 
#include &lt;boost/system/system_error.hpp&gt; 
#include &lt;iostream&gt; 

int main() 
{ 
  try 
  { 
    std::cout &lt;&lt; boost::asio::ip::host_name() &lt;&lt; std::endl; 
  } 
  catch (boost::system::system_error &amp;e) 
  { 
    boost::system::error_code ec = e.code(); 
    std::cerr &lt;&lt; ec.value() &lt;&lt; std::endl; 
    std::cerr &lt;&lt; ec.category().name() &lt;&lt; std::endl; 
  } 
} </pre>
<ul class="programlisting"><li><a class="programlisting" href="src/15.2.5/main.cpp">Download source code</a></li></ul>
<p>The free-standing <code class="function">boost::asio::ip::host_name()</code> function is provided in two versions: One expecting an argument of type <code class="classname">boost::system::error_code</code> and one expecting no arguments. The second version will throw an exception of type <code class="exceptionname">boost::system::system_error</code> in case of an error. The exception transports the error code of type <code class="classname">boost::system::error_code</code> accordingly.</p>
</div>
<hr>
<h2 class="title">
<a name="errorhandling_exception"></a>15.3 Boost.Exception</h2>
<div class="sect1">
<p>The <a class="link" href="http://www.boost.org/libs/exception/">Boost.Exception</a> library offers a new exception type <code class="exceptionname">boost::exception</code> allowing to add information to an exception after it has been thrown. It is defined in <code class="filename">boost/exception/exception.hpp</code>. Since Boost.Exception spreads its classes and functions over multiple header files, the following example rather accesses <code class="filename">boost/exception/all.hpp</code> to avoid including the header files individually.</p>
<pre class="programlisting">#include &lt;boost/exception/all.hpp&gt; 
#include &lt;boost/lexical_cast.hpp&gt; 
#include &lt;boost/shared_array.hpp&gt; 
#include &lt;exception&gt; 
#include &lt;string&gt; 
#include &lt;iostream&gt; 

typedef boost::error_info&lt;struct tag_errmsg, std::string&gt; errmsg_info; 

class allocation_failed : 
  public boost::exception, 
  public std::exception 
{ 
public: 
  allocation_failed(std::size_t size) 
    : what_("allocation of " + boost::lexical_cast&lt;std::string&gt;(size) + " bytes failed") 
  { 
  } 

  virtual const char *what() const throw() 
  { 
    return what_.c_str(); 
  } 

private: 
  std::string what_; 
}; 

boost::shared_array&lt;char&gt; allocate(std::size_t size) 
{ 
  if (size &gt; 1000) 
    throw allocation_failed(size); 
  return boost::shared_array&lt;char&gt;(new char[size]); 
} 

void save_configuration_data() 
{ 
  try 
  { 
    boost::shared_array&lt;char&gt; a = allocate(2000); 
    // saving configuration data ... 
  } 
  catch (boost::exception &amp;e) 
  { 
    e &lt;&lt; errmsg_info("saving configuration data failed"); 
    throw; 
  } 
} 

int main() 
{ 
  try 
  { 
    save_configuration_data(); 
  } 
  catch (boost::exception &amp;e) 
  { 
    std::cerr &lt;&lt; boost::diagnostic_information(e); 
  } 
} </pre>
<ul class="programlisting"><li><a class="programlisting" href="src/15.3.1/main.cpp">Download source code</a></li></ul>
<p>The example calls the function <code class="function">save_configuration_data()</code> inside <code class="function">main()</code> which in turn calls the <code class="function">allocate()</code> function. <code class="function">allocate()</code> allocates memory dynamically; however, it checks whether or not a certain limit is exceeded. This limit is arbitrarily set to 1,000 bytes in the example.</p>
<p>If <code class="function">allocate()</code> is called with a value greater than 1,000, an exception is thrown accordingly which is the case inside the <code class="function">save_configuration_data()</code> function. The function supposedly saves configuration data in the dynamically allocated memory as indicated by the comment.</p>
<p>The purpose of the example is to actually throw the exception in order to demonstrate Boost.Exception. The exception, thrown by <code class="function">allocate()</code>, is of type <code class="exceptionname">allocation_failed</code> and is derived from both <code class="exceptionname">boost::exception</code> and <code class="exceptionname">std::exception</code>.</p>
<p>Deriving from <code class="exceptionname">std::exception</code> is certainly not necessary. <code class="exceptionname">allocation_failed</code> could have also been derived from a different class hierarchy in order to embed it inside an existing framework. While the above example uses the class hierarchy defined by the C++ standard, deriving <code class="exceptionname">allocation_failed</code> solely from <code class="exceptionname">boost::exception</code> would have also been sufficient.</p>
<p>When throwing an exception of type <code class="exceptionname">allocation_failed</code>, the size of the memory expected to be allocated, is stored inside the exception to alleviate debugging of the corresponding application. If more memory is requested than can be provided by <code class="function">allocate()</code>, the root cause for the exception can be easily spotted.</p>
<p>If <code class="function">allocate()</code> is called by only one function (in the example <code class="function">save_configuration_data()</code>), this information is sufficient to locate the issue. However, in more complex applications with many functions calling <code class="function">allocate()</code> to dynamically allocate memory, the information is no longer sufficient to effectively debug the application. In these cases, it rather would help to actually know which function tried to allocate more memory than <code class="function">allocate()</code> can provide. Adding more information to the exception in these cases would help the debugging process tremendously.</p>
<p>The particular challenge is that <code class="function">allocate()</code> does not have information such as the caller name in order to add it to the exception accordingly.</p>
<p>Boost.Exception offers the following solution: Information can be added to an exception at all times by defining a data type based on <code class="classname">boost::error_info</code> for every information that should be added to the exception.</p>
<p><code class="classname">boost::error_info</code> is a template expecting two arguments: The first argument is a so-called tag, uniquely identifying the newly created data type. Commonly, a structure with a unique name is utilized. The second argument  refers to the data type of the information stored inside the exception.</p>
<p>The application defined a new data type <code class="type">errmsg_info</code>, uniquely identifiable via the <code class="classname">tag_errmsg</code> structure, which stores a string of type <code class="classname">std::string</code>.</p>
<p>Inside the <code class="code">catch</code> handler of <code class="function">save_configuration_data()</code>, the data type <code class="type">tag_errmsg</code> is accessed to create an object, initialized with the string "saving configuration data failed", to add additional information to the exception of type <code class="classname">boost::exception</code> via the <code class="methodname">operator&lt;&lt;()</code> operator. The exception is then re-thrown accordingly.</p>
<p>The exception now not only carries the size of memory expected to be dynamically allocated, but also the description of the error added inside the <code class="function">save_configuration_data()</code> function. This description certainly helps while debugging since it now becomes clear which function tried to allocate more memory than can be provided.</p>
<p>To retrieve all available information from an exception, the <code class="function">boost::diagnostic_information()</code> function can be used as seen in the example inside the <code class="code">catch</code> handler of <code class="function">main()</code>. For every exception passed, <code class="function">boost::diagnostic_information()</code> not only calls the <code class="methodname">what()</code> method but also accesses all additional information stored inside the exception. A string of type <code class="classname">std::string</code> is returned that can e.g. be written to the standard output stream.</p>
<p>Above application compiled with Visual C++ 2008 displays the following message:</p>
<pre class="screen">Throw in function (unknown)
Dynamic exception type: class allocation_failed
std::exception::what: allocation of 2000 bytes failed
[struct tag_errmsg *] = saving configuration data failed</pre>
<p>As can be seen, the message contains the data type of the exception, the error message as retrieved from the <code class="methodname">what()</code> method, and the description including the corresponding name of the structure.</p>
<p><code class="function">boost::diagnostic_information()</code> checks at run-time whether or not a given exception is derived from <code class="exceptionname">std::exception</code>. Only if it is, the <code class="methodname">what()</code> method is actually called.</p>
<p>The name of the function that has thrown the exception of type <code class="exceptionname">allocation_failed</code> is indicated as "unknown" in the message.</p>
<p>Boost.Exception provides a macro to throw an exception including not only the name of the function but also additional information such as the file name and the line number.</p>
<pre class="programlisting">#include &lt;boost/exception/all.hpp&gt; 
#include &lt;boost/lexical_cast.hpp&gt; 
#include &lt;boost/shared_array.hpp&gt; 
#include &lt;exception&gt; 
#include &lt;string&gt; 
#include &lt;iostream&gt; 

typedef boost::error_info&lt;struct tag_errmsg, std::string&gt; errmsg_info; 

class allocation_failed : 
  public std::exception 
{ 
public: 
  allocation_failed(std::size_t size) 
    : what_("allocation of " + boost::lexical_cast&lt;std::string&gt;(size) + " bytes failed") 
  { 
  } 

  virtual const char *what() const throw() 
  { 
    return what_.c_str(); 
  } 

private: 
  std::string what_; 
}; 

boost::shared_array&lt;char&gt; allocate(std::size_t size) 
{ 
  if (size &gt; 1000) 
    BOOST_THROW_EXCEPTION(allocation_failed(size)); 
  return boost::shared_array&lt;char&gt;(new char[size]); 
} 

void save_configuration_data() 
{ 
  try 
  { 
    boost::shared_array&lt;char&gt; a = allocate(2000); 
    // saving configuration data ... 
  } 
  catch (boost::exception &amp;e) 
  { 
    e &lt;&lt; errmsg_info("saving configuration data failed"); 
    throw; 
  } 
} 

int main() 
{ 
  try 
  { 
    save_configuration_data(); 
  } 
  catch (boost::exception &amp;e) 
  { 
    std::cerr &lt;&lt; boost::diagnostic_information(e); 
  } 
} </pre>
<ul class="programlisting"><li><a class="programlisting" href="src/15.3.2/main.cpp">Download source code</a></li></ul>
<p>By using the macro <code class="code">BOOST_THROW_EXCEPTION</code> instead of <code class="code">throw</code>, additional information such as function name, file name and line number are automatically added to the exception. This only works if the compiler supports corresponding macros though. While macros such as <code class="code">__FILE__</code> and <code class="code">__LINE__</code> are defined by the C++ standard, there is no standardized macro for returning the name of the current function. Since many of the compiler manufacturers provide such a macro, <code class="code">BOOST_THROW_EXCEPTION</code> tries to identify the underlying compiler and utilize the corresponding macro accordingly. Compiled with Visual C++ 2008, the above application displays the following message:</p>
<pre class="screen">.\main.cpp(31): Throw in function class boost::shared_array&lt;char&gt; __cdecl allocate(unsigned int)
Dynamic exception type: class boost::exception_detail::clone_impl&lt;struct boost::exception_detail::error_info_injector&lt;class allocation_failed&gt; &gt;
std::exception::what: allocation of 2000 bytes failed
[struct tag_errmsg *] = saving configuration data failed</pre>
<p>The code compiles without errors even though the <code class="exceptionname">allocation_failed</code> class is no longer derived from <code class="exceptionname">boost::exception</code>. <code class="code">BOOST_THROW_EXCEPTION</code> accesses a function named <code class="function">boost::enable_error_info()</code> that dynamically identifies whether or not an exception is derived from <code class="exceptionname">boost::exception</code>. If not, it automatically creates a new exception type derived both from the specified type and <code class="exceptionname">boost::exception</code>. This mechanism is the reason for the above message to not display <code class="exceptionname">allocation_failed</code> only.</p>
<p>Finally, this section concludes with an example to selectively access information added to an exception.</p>
<pre class="programlisting">#include &lt;boost/exception/all.hpp&gt; 
#include &lt;boost/lexical_cast.hpp&gt; 
#include &lt;boost/shared_array.hpp&gt; 
#include &lt;exception&gt; 
#include &lt;string&gt; 
#include &lt;iostream&gt; 

typedef boost::error_info&lt;struct tag_errmsg, std::string&gt; errmsg_info; 

class allocation_failed : 
  public std::exception 
{ 
public: 
  allocation_failed(std::size_t size) 
    : what_("allocation of " + boost::lexical_cast&lt;std::string&gt;(size) + " bytes failed") 
  { 
  } 

  virtual const char *what() const throw() 
  { 
    return what_.c_str(); 
  } 

private: 
  std::string what_; 
}; 

boost::shared_array&lt;char&gt; allocate(std::size_t size) 
{ 
  if (size &gt; 1000) 
    BOOST_THROW_EXCEPTION(allocation_failed(size)); 
  return boost::shared_array&lt;char&gt;(new char[size]); 
} 

void save_configuration_data() 
{ 
  try 
  { 
    boost::shared_array&lt;char&gt; a = allocate(2000); 
    // saving configuration data ... 
  } 
  catch (boost::exception &amp;e) 
  { 
    e &lt;&lt; errmsg_info("saving configuration data failed"); 
    throw; 
  } 
} 

int main() 
{ 
  try 
  { 
    save_configuration_data(); 
  } 
  catch (boost::exception &amp;e) 
  { 
    std::cerr &lt;&lt; *boost::get_error_info&lt;errmsg_info&gt;(e); 
  } 
} </pre>
<ul class="programlisting"><li><a class="programlisting" href="src/15.3.3/main.cpp">Download source code</a></li></ul>
<p>The example does not utilize <code class="function">boost::diagnostic_information()</code> but rather uses <code class="function">boost::get_error_info()</code> to directly access the error message of type <code class="classname">errmsg_info</code>. <code class="function">boost::get_error_info()</code> returns a smart pointer of type <code class="classname">boost::shared_ptr</code>. In case the argument passed is not of type <code class="exceptionname">boost::exception</code>, a null pointer is returned accordingly. If the <code class="code">BOOST_THROW_EXCEPTION</code> macro is always used to throw an exception, it is guaranteed that the exception is derived from <code class="exceptionname">boost::exception</code> - there is no need to check the returned smart pointer for null in these cases.</p>
</div>
</div>
<hr class="hrfoot">
<p class="copyright">Copyright © 2008-2010 
        <a class="link" href="mailto:boris@highscore.de">Boris Schäling</a>
      </p>
</body>
</html>
